from typing import List, Optional
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from uuid import UUID

from app.models.maintenance_plan import MaintenancePlan, PlanFrequency
from app.models.maintenance_record import MaintenanceRecord, MaintenanceStatus
from app.schemas.maintenance_plan import (
    MaintenancePlanCreate, 
    MaintenancePlanUpdate,
    MaintenancePlanFilter,
    MaintenancePlanExecution
)
from app.schemas.maintenance_record import MaintenanceRecordCreate

class MaintenancePlanService:
    """维护计划服务类"""
    
    def get(self, db: Session, plan_id: UUID) -> Optional[MaintenancePlan]:
        """获取单个维护计划"""
        return db.query(MaintenancePlan).filter(MaintenancePlan.id == plan_id).first()
    
    def get_multi(
        self, 
        db: Session, 
        *, 
        skip: int = 0, 
        limit: int = 100,
        filters: Optional[MaintenancePlanFilter] = None
    ) -> List[MaintenancePlan]:
        """获取维护计划列表"""
        query = db.query(MaintenancePlan)
        
        if filters:
            if filters.device_id:
                query = query.filter(MaintenancePlan.device_id == filters.device_id)
            if filters.maintenance_type:
                query = query.filter(MaintenancePlan.maintenance_type == filters.maintenance_type)
            if filters.frequency:
                query = query.filter(MaintenancePlan.frequency == filters.frequency)
            if filters.is_active is not None:
                query = query.filter(MaintenancePlan.is_active == filters.is_active)
            if filters.default_assignee:
                query = query.filter(MaintenancePlan.default_assignee == filters.default_assignee)
            if filters.due_soon:
                # 即将到期的计划（未来7天内）
                due_date = datetime.now() + timedelta(days=7)
                query = query.filter(
                    and_(
                        MaintenancePlan.next_execution <= due_date,
                        MaintenancePlan.is_active == True
                    )
                )
            if filters.overdue:
                # 逾期的计划
                query = query.filter(
                    and_(
                        MaintenancePlan.next_execution < datetime.now(),
                        MaintenancePlan.is_active == True
                    )
                )
        
        return query.order_by(MaintenancePlan.next_execution.asc()).offset(skip).limit(limit).all()
    
    def create(self, db: Session, *, obj_in: MaintenancePlanCreate, created_by: UUID) -> MaintenancePlan:
        """创建维护计划"""
        obj_data = obj_in.model_dump()
        obj_data["created_by"] = created_by
        
        # 计算下次执行时间
        next_execution = self._calculate_next_execution(obj_in.start_date, obj_in.frequency, obj_in.interval_days)
        obj_data["next_execution"] = next_execution
        
        db_obj: MaintenancePlan = MaintenancePlan(**obj_data)
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def update(self, db: Session, *, db_obj: MaintenancePlan, obj_in: MaintenancePlanUpdate) -> MaintenancePlan:
        """更新维护计划"""
        obj_data = obj_in.model_dump(exclude_unset=True)
        
        # 如果更新了频率相关字段，重新计算下次执行时间
        if any(key in obj_data for key in ['frequency', 'interval_days', 'start_date']):
            frequency = obj_data.get('frequency', db_obj.frequency)  # type: ignore
            interval_days = obj_data.get('interval_days', db_obj.interval_days)  # type: ignore
            start_date = obj_data.get('start_date', db_obj.start_date)  # type: ignore
            
            # 如果有最后执行时间，从最后执行时间计算，否则从开始时间计算
            base_date = db_obj.last_execution if db_obj.last_execution else start_date  # type: ignore
            if isinstance(base_date, datetime):
                obj_data["next_execution"] = self._calculate_next_execution(base_date, frequency, interval_days)
            else:
                obj_data["next_execution"] = self._calculate_next_execution(start_date, frequency, interval_days)
        
        for field, value in obj_data.items():
            if hasattr(db_obj, field):
                setattr(db_obj, field, value)
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def activate_plan(self, db: Session, *, plan_id: UUID) -> Optional[MaintenancePlan]:
        """激活维护计划"""
        db_obj = self.get(db, plan_id)
        if not db_obj:
            return None
        
        db_obj.is_active = True  # type: ignore
        # 重新计算下次执行时间
        base_date = db_obj.last_execution if db_obj.last_execution else db_obj.start_date  # type: ignore
        db_obj.next_execution = self._calculate_next_execution(base_date, db_obj.frequency, db_obj.interval_days)  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def deactivate_plan(self, db: Session, *, plan_id: UUID) -> Optional[MaintenancePlan]:
        """停用维护计划"""
        db_obj = self.get(db, plan_id)
        if not db_obj:
            return None
        
        db_obj.is_active = False  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        return db_obj
    
    def execute_plan(
        self, 
        db: Session, 
        *, 
        plan_id: UUID, 
        execution_date: Optional[datetime] = None,
        created_by: UUID
    ) -> Optional[MaintenancePlanExecution]:
        """执行维护计划（创建维护记录）"""
        db_obj = self.get(db, plan_id)
        if not db_obj:
            return None
        
        if not db_obj.is_active:  # type: ignore
            raise ValueError("不能执行已停用的维护计划")
        
        if execution_date is None:
            execution_date = datetime.now()
        
        # 创建维护记录
        record_data = MaintenanceRecordCreate(
            device_id=db_obj.device_id,  # type: ignore
            maintenance_type=db_obj.maintenance_type,  # type: ignore
            title=db_obj.title,  # type: ignore
            description=db_obj.template_description or db_obj.description,  # type: ignore
            priority=db_obj.priority,  # type: ignore
            scheduled_at=execution_date,
            estimated_duration=db_obj.estimated_duration,  # type: ignore
            assigned_to=db_obj.default_assignee  # type: ignore
        )
        
        # 这里需要导入维护记录服务来创建记录
        from app.services.maintenance_record import MaintenanceRecordService
        record_service = MaintenanceRecordService()
        created_record = record_service.create(db, obj_in=record_data, created_by=created_by)
        
        # 更新计划的执行信息
        db_obj.last_execution = execution_date  # type: ignore
        db_obj.next_execution = self._calculate_next_execution(execution_date, db_obj.frequency, db_obj.interval_days)  # type: ignore
        
        db.add(db_obj)
        db.commit()
        db.refresh(db_obj)
        
        return MaintenancePlanExecution(
            execution_date=execution_date,
            next_execution=db_obj.next_execution,  # type: ignore
            created_record_id=created_record.id  # type: ignore
        )
    
    def get_due_plans(self, db: Session, *, advance_days: int = 0) -> List[MaintenancePlan]:
        """获取到期的维护计划"""
        due_date = datetime.now() + timedelta(days=advance_days)
        return db.query(MaintenancePlan).filter(
            and_(
                MaintenancePlan.next_execution <= due_date,
                MaintenancePlan.is_active == True
            )
        ).all()
    
    def auto_create_maintenance_records(self, db: Session, created_by: UUID) -> List[MaintenancePlanExecution]:
        """自动创建到期的维护记录"""
        due_plans = self.get_due_plans(db)
        executions = []
        
        for plan in due_plans:
            if plan.auto_create_records and plan.next_execution <= datetime.now():  # type: ignore
                try:
                    execution = self.execute_plan(db, plan_id=plan.id, created_by=created_by)  # type: ignore
                    if execution:
                        executions.append(execution)
                except Exception as e:
                    # 记录错误但继续处理其他计划
                    print(f"Failed to execute plan {plan.id}: {str(e)}")
                    continue
        
        return executions
    
    def _calculate_next_execution(
        self, 
        base_date: datetime, 
        frequency: PlanFrequency, 
        interval_days: Optional[int] = None
    ) -> datetime:
        """计算下次执行时间"""
        if frequency == PlanFrequency.DAILY:
            return base_date + timedelta(days=1)
        elif frequency == PlanFrequency.WEEKLY:
            return base_date + timedelta(weeks=1)
        elif frequency == PlanFrequency.MONTHLY:
            return base_date + relativedelta(months=1)
        elif frequency == PlanFrequency.QUARTERLY:
            return base_date + relativedelta(months=3)
        elif frequency == PlanFrequency.SEMI_ANNUALLY:
            return base_date + relativedelta(months=6)
        elif frequency == PlanFrequency.ANNUALLY:
            return base_date + relativedelta(years=1)
        elif frequency == PlanFrequency.CUSTOM and interval_days:
            return base_date + timedelta(days=interval_days)
        else:
            # 默认返回30天后
            return base_date + timedelta(days=30)
    
    def remove(self, db: Session, *, id: UUID) -> Optional[MaintenancePlan]:
        """删除维护计划"""
        obj = db.query(MaintenancePlan).get(id)
        if obj:
            db.delete(obj)
            db.commit()
        return obj